use std::collections::HashMap;

use serde::{Deserialize, Deserializer};

static ORDER_MATCH: once_cell::sync::Lazy<regex::Regex> = once_cell::sync::Lazy::new(|| {
    regex::Regex::new(r"^\w+(-desc|-asc)?(,\w+(-desc|-asc)?)*$").unwrap()
});
static ORDER_MATCH1: once_cell::sync::Lazy<regex::Regex> =
    once_cell::sync::Lazy::new(|| regex::Regex::new(r"^\w+(-desc|-asc)*$").unwrap());

#[derive(Debug, Clone)]
pub struct Order(pub(crate) String, pub(crate) bool);

impl Order {
    pub fn new(key: String, asc: bool) -> Self {
        Self(key, asc)
    }

    pub fn key(&self) -> &str {
        &self.0
    }

    pub fn is_asc(&self) -> bool {
        self.1
    }

    pub fn parse(value: &str) -> Vec<Self> {
        if ORDER_MATCH.is_match(value) {
            value
                .split(",")
                .map(|f| f.split("-"))
                .map(|mut f| {
                    Self(
                        f.next().unwrap().to_owned(),
                        f.next().map(|f| f == "asc").unwrap_or(true),
                    )
                })
                .collect()
        } else {
            vec![]
        }
    }

    pub fn parse_to_map(value: &str) -> HashMap<String, Self> {
        let mut map = HashMap::new();
        if ORDER_MATCH.is_match(value) {
            value
                .split(",")
                .map(|f| f.split("-"))
                .map(|mut f| {
                    Self(
                        f.next().unwrap().to_owned(),
                        f.next().map(|f| f == "asc").unwrap_or(true),
                    )
                })
                .for_each(|f| {
                    map.insert(f.0.clone(), f);
                });
        }
        map
    }
}

pub fn order_vec_deserialize<'de, D>(deserializer: D) -> Result<Vec<Order>, D::Error>
where
    D: Deserializer<'de>,
{
    let s = String::deserialize(deserializer)?;
    Ok(Order::parse(&s))
}

#[derive(Debug, Default, Clone)]
pub struct Orders(Vec<(String, bool)>);

impl std::ops::Deref for Orders {
    type Target = Vec<(String, bool)>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl From<&str> for Orders {
    fn from(value: &str) -> Self {
        Self(if ORDER_MATCH.is_match(value) {
            value
                .split(",")
                .map(|f| f.split("-"))
                .map(|mut f| {
                    (
                        f.next().unwrap().to_owned(),
                        f.next().map(|f| f == "asc").unwrap_or(true),
                    )
                })
                .collect()
        } else {
            vec![]
        })
    }
}

impl<'de> Deserialize<'de> for Orders {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        String::deserialize(deserializer).map(|f| f.as_str().into())
    }
}

impl Orders {
    pub fn merge(mut self, orders: &Self) -> Self {
        self.0.extend(orders.0.clone());
        self
    }
}
